Apply patch by Vytautas Liuolia for changing the startup notification id
authorEmmanuele Bassi <ebassi@gnome.org>
Tue, 13 Mar 2007 17:03:54 +0000 (17:03 +0000)
committerEmmanuele Bassi <ebassi@src.gnome.org>
Tue, 13 Mar 2007 17:03:54 +0000 (17:03 +0000)
2007-03-13  Emmanuele Bassi  <ebassi@gnome.org>

Apply patch by Vytautas Liuolia for changing the startup
notification id on a window in the X11 backend. (#347375)

* gdk/gdk.h:
* gdk/gdkx.h:
* gdk/x11/gdkdisplay-x11.c: Add gdk_notify_startup_complete_wit_id()
and gdk_x11_display_get_startup_notification_id().

* gdk/gdkwindow.h:
* gdk/x11/gdkwindow-x11.c: Add gdk_window_set_startup_id().

* gtk/gtkwindow.h:
* gtk/gtkwindow.c: Add gtk_window_set_startup_id(), used to
change the startup notification id.

(gtk_window_class_init), (gtk_window_init),
(gtk_window_set_property): Add write-only "startup-id" property
to GtkWindow.

(gtk_window_realize): Set the startup notification id
on a GtkWindow if it's valid.

(gtk_window_map): If we have another valid startup notification
id then finish the notification process.

svn path=/trunk/; revision=17508

ChangeLog
gdk/gdk.h
gdk/gdkwindow.h
gdk/x11/gdkdisplay-x11.c
gdk/x11/gdkwindow-x11.c
gdk/x11/gdkx.h
gtk/gtkwindow.c
gtk/gtkwindow.h

index f90e146e96641e65a9a2c102bdd0ea92d9c8eee8..69728d6c3da56e14aa0b2a237fe1ad7fde67f96b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2007-03-13  Emmanuele Bassi  <ebassi@gnome.org>
+
+       Apply patch by Vytautas Liuolia for changing the startup
+       notification id on a window in the X11 backend. (#347375)
+
+       * gdk/gdk.h:
+       * gdk/gdkx.h:
+       * gdk/x11/gdkdisplay-x11.c: Add gdk_notify_startup_complete_wit_id()
+       and gdk_x11_display_get_startup_notification_id().
+
+       * gdk/gdkwindow.h:
+       * gdk/x11/gdkwindow-x11.c: Add gdk_window_set_startup_id().
+
+       * gtk/gtkwindow.h:
+       * gtk/gtkwindow.c: Add gtk_window_set_startup_id(), used to
+       change the startup notification id.
+       
+       (gtk_window_class_init), (gtk_window_init),
+       (gtk_window_set_property): Add write-only "startup-id" property
+       to GtkWindow.
+
+       (gtk_window_realize): Set the startup notification id
+       on a GtkWindow if it's valid.
+
+       (gtk_window_map): If we have another valid startup notification
+       id then finish the notification process.
+
 2007-03-13  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtknotebook.c (gtk_notebook_real_insert_page):
index 1a7a596c103890afdfa959833e154bb3c5f9f543..d84d304a742ed0d2a6178d75fe016bfa7960912b 100644 (file)
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -177,6 +177,8 @@ gboolean gdk_event_send_client_message_for_display (GdkDisplay *display,
 
 void gdk_notify_startup_complete (void);
 
+void gdk_notify_startup_complete_with_id (const gchar* startup_id);
+
 /* Threading
  */
 
index 8380aa56e351e7555e3ac3de38ed72b0b23ed57d..be1fc2b1e3c60ffc80ffe4cb7ad75009d78b3a23 100644 (file)
@@ -482,6 +482,8 @@ void              gdk_window_set_title         (GdkWindow     *window,
                                            const gchar   *title);
 void          gdk_window_set_role          (GdkWindow       *window,
                                            const gchar     *role);
+void          gdk_window_set_startup_id    (GdkWindow       *window,
+                                           const gchar     *startup_id);                                         
 void          gdk_window_set_transient_for (GdkWindow       *window, 
                                            GdkWindow       *parent);
 void         gdk_window_set_background  (GdkWindow       *window,
index fa1524e0adaeaa09bc72a95302a563e1f744c553..ace29b2cfc87e7a08c239fd48d31d7bd56231497 100644 (file)
@@ -1079,7 +1079,36 @@ gdk_notify_startup_complete (void)
   if (!G_LIKELY (display_x11->trusted_client))
     return;
 
-  escaped_id = escape_for_xmessage (display_x11->startup_notification_id);
+  gdk_notify_startup_complete_with_id (display_x11->startup_notification_id);
+}
+
+/**
+ * gdk_notify_startup_complete_with_id:
+ * @startup_id: a startup-notification identifier, for which notification
+ *              process should be completed
+ * 
+ * Indicates to the GUI environment that the application has finished
+ * loading, using a given identifier.
+ * 
+ * GTK+ will call this function automatically for #GtkWindow with custom
+ * startup-notification identifier unless
+ * gtk_window_set_auto_startup_notification() is called to disable
+ * that feature.
+ *
+ * Since: 2.12
+ **/
+void
+gdk_notify_startup_complete_with_id (const gchar* startup_id)
+{
+  GdkDisplay *display;
+  gchar *escaped_id;
+  gchar *message;
+
+  display = gdk_display_get_default ();
+  if (!display)
+    return;
+
+  escaped_id = escape_for_xmessage (startup_id);
   message = g_strdup_printf ("remove: ID=%s", escaped_id);
   g_free (escaped_id);
 
@@ -1091,7 +1120,6 @@ gdk_notify_startup_complete (void)
   g_free (message);
 }
 
-
 /**
  * gdk_display_supports_selection_notification:
  * @display: a #GdkDisplay
@@ -1291,5 +1319,20 @@ gdk_display_supports_input_shapes (GdkDisplay *display)
 }
 
 
+/**
+ * gdk_x11_display_get_startup_notification_id:
+ * @display: a #GdkDisplay
+ *
+ * Returns: the startup notification ID for 
+ * @display.
+ *
+ * Since: 2.12
+ */
+G_CONST_RETURN gchar *
+gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
+{
+  return GDK_DISPLAY_X11 (display)->startup_notification_id;
+}
+
 #define __GDK_DISPLAY_X11_C__
 #include "gdkaliasdef.c"
index dc464347758c9ab9bc9846c54facf45f739492c5..c0226a6815994046cd0430fd05f46d0cce46ba52 100644 (file)
@@ -2896,6 +2896,40 @@ gdk_window_set_role (GdkWindow   *window,
     }
 }
 
+/**
+ * gdk_window_set_startup_id:
+ * @window: a toplevel #GdkWindow
+ * @startup_id: a string with startup-notification identifier
+ *
+ * When using GTK+, typically you should use gtk_window_set_startup_id()
+ * instead of this low-level function.
+ *
+ * Since: 2.12
+ *
+ **/
+void          
+gdk_window_set_startup_id (GdkWindow   *window,
+                    const gchar *startup_id)
+{
+  GdkDisplay *display;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  display = gdk_drawable_get_display (window);
+
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      if (startup_id)
+       XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"), 
+                        gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+                        PropModeReplace, startup_id, strlen (startup_id));
+      else
+       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+                        gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
+    }
+}
+
 /**
  * gdk_window_set_transient_for:
  * @window: a toplevel #GdkWindow
index f07a5883e776ef6d2963e801c031f5e5dcc07f2c..9563e1b814963d632e11f54dcad8f3a2bdd66a8c 100644 (file)
@@ -142,6 +142,8 @@ gpointer      gdk_xid_table_lookup_for_display (GdkDisplay *display,
 guint32       gdk_x11_get_server_time  (GdkWindow       *window);
 guint32       gdk_x11_display_get_user_time (GdkDisplay *display);
 
+G_CONST_RETURN gchar *gdk_x11_display_get_startup_notification_id (GdkDisplay *display);
+
 void          gdk_x11_display_set_cursor_theme (GdkDisplay  *display,
                                                const gchar *theme,
                                                const gint   size);
index 3766f38e18dbb3f6f6ddec9f352ad9803c1a443e..b780c61c72c08a6f1cb05a151394c9b66060e17f 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <config.h>
 #include <string.h>
+#include <stdlib.h>
+#include <errno.h>
 #include <limits.h>
 #include "gdk/gdk.h"
 #include "gdk/gdkkeysyms.h"
@@ -95,6 +97,9 @@ enum {
   PROP_IS_ACTIVE,
   PROP_HAS_TOPLEVEL_FOCUS,
   
+  /* Writeonly properties */
+  PROP_STARTUP_ID,
+  
   LAST_ARG
 };
 
@@ -177,6 +182,8 @@ struct _GtkWindowPrivate
 
   guint reset_type_hint : 1;
   GdkWindowTypeHint type_hint;
+
+  gchar *startup_id;
 };
 
 static void gtk_window_dispose            (GObject           *object);
@@ -344,6 +351,33 @@ add_arrow_bindings (GtkBindingSet    *binding_set,
                                 GTK_TYPE_DIRECTION_TYPE, direction);
 }
 
+static guint32
+extract_time_from_startup_id (const gchar* startup_id)
+{
+  gchar *timestr = g_strrstr (startup_id, "_TIME");
+  guint32 retval = GDK_CURRENT_TIME;
+
+  if (timestr)
+    {
+      gchar *end;
+      guint32 timestamp; 
+    
+      /* Skip past the "_TIME" part */
+      timestr += 5;
+    
+      timestamp = strtoul (timestr, &end, 0);
+      if (end != timestr && errno == 0)
+        retval = timestamp;
+    }
+
+  return retval;
+}
+
+static gboolean
+startup_id_is_fake (const gchar* startup_id)
+{
+  return strncmp (startup_id, "_TIME", 5) == 0;
+}
 
 static void
 gtk_window_class_init (GtkWindowClass *klass)
@@ -429,6 +463,23 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                        P_("Unique identifier for the window to be used when restoring a session"),
                                                        NULL,
                                                        GTK_PARAM_READWRITE));
+                                                       
+  /**
+   * GtkWindow:startup-id:
+   *
+   * The :startup-id is a write-only property for setting window's
+   * startup notification identifier. See gtk_window_set_startup_id()
+   * for more details.
+   *
+   * Since: 2.12
+   */                                                  
+  g_object_class_install_property (gobject_class,
+                                   PROP_ROLE,
+                                   g_param_spec_string ("startup-id",
+                                                       P_("Startup ID"),
+                                                       P_("Unique startup identifier for the window used by startup-notification"),
+                                                       NULL,
+                                                       GTK_PARAM_WRITABLE));
 
   g_object_class_install_property (gobject_class,
                                    PROP_ALLOW_SHRINK,
@@ -810,6 +861,7 @@ gtk_window_init (GtkWindow *window)
   priv->focus_on_map = TRUE;
   priv->deletable = TRUE;
   priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
+  priv->startup_id = NULL;
 
   colormap = _gtk_widget_peek_colormap ();
   if (colormap)
@@ -846,6 +898,9 @@ gtk_window_set_property (GObject      *object,
     case PROP_ROLE:
       gtk_window_set_role (window, g_value_get_string (value));
       break;
+    case PROP_STARTUP_ID:
+      gtk_window_set_startup_id (window, g_value_get_string (value));
+      break; 
     case PROP_ALLOW_SHRINK:
       window->allow_shrink = g_value_get_boolean (value);
       gtk_widget_queue_resize (GTK_WIDGET (window));
@@ -1200,6 +1255,60 @@ gtk_window_set_role (GtkWindow   *window,
   g_object_notify (G_OBJECT (window), "role");
 }
 
+/**
+ * gtk_window_set_startup_id:
+ * @window: a #GtkWindow
+ * @startup_id: a string with startup-notification identifier
+ *
+ * Startup notification identifiers are used by desktop environment to 
+ * track application startup, to provide user feedback and other 
+ * features. This function changes the corresponding property on the
+ * underlying GdkWindow. Normally, startup identifier is managed 
+ * automatically and you should only use this function in special cases
+ * like transferring focus from other processes. You should use this
+ * function before calling gtk_window_present() or any equivalent
+ * function generating a window map event.
+ *
+ * This function is only useful on X11, not with other GTK+ targets.
+ * 
+ * Since: 2.12
+ **/
+void
+gtk_window_set_startup_id (GtkWindow   *window,
+                           const gchar *startup_id)
+{
+  GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+  
+  g_free (priv->startup_id);
+  priv->startup_id = g_strdup (startup_id);
+  
+  if (GTK_WIDGET_REALIZED (window))
+    {
+      /* Here we differentiate real and "fake" startup notification IDs,
+       * constructed on purpose just to pass interaction timestamp
+       */  
+      if (startup_id_is_fake (priv->startup_id))
+        {
+          guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
+
+          gtk_window_present_with_time (window, timestamp);
+        }
+      else 
+        {
+          gdk_window_set_startup_id (GTK_WIDGET (window)->window,
+                                     priv->startup_id);
+          
+          /* If window is mapped, terminate the startup-notification too */
+          if (GTK_WIDGET_MAPPED (window) && !disable_startup_notification)
+            gdk_notify_startup_complete_with_id (priv->startup_id);
+        }
+    }
+
+  g_object_notify (G_OBJECT (window), "startup-id");
+}
+
 /**
  * gtk_window_get_role:
  * @window: a #GtkWindow
@@ -4149,11 +4258,22 @@ gtk_window_map (GtkWidget *widget)
   if (window->frame)
     gdk_window_show (window->frame);
 
-  if (!disable_startup_notification &&
-      !sent_startup_notification)
+  if (!disable_startup_notification)
     {
-      sent_startup_notification = TRUE;
-      gdk_notify_startup_complete ();
+      /* Do we have a custom startup-notification id? */
+      if (priv->startup_id != NULL)
+        {
+          /* Make sure we have a "real" id */
+          if (!startup_id_is_fake (priv->startup_id)) 
+            gdk_notify_startup_complete_with_id (priv->startup_id);
+            
+          priv->startup_id = NULL;
+        }
+      else if (!sent_startup_notification)
+        {
+          sent_startup_notification = TRUE;
+          gdk_notify_startup_complete ();
+        }
     }
 }
 
@@ -4223,7 +4343,6 @@ gtk_window_realize (GtkWidget *widget)
   GtkWindowPrivate *priv;
   
   window = GTK_WINDOW (widget);
-
   priv = GTK_WINDOW_GET_PRIVATE (window);
 
   /* ensure widget tree is properly size allocated */
@@ -4377,6 +4496,17 @@ gtk_window_realize (GtkWidget *widget)
     gdk_window_set_modal_hint (widget->window, TRUE);
   else
     gdk_window_set_modal_hint (widget->window, FALSE);
+    
+  if (priv->startup_id)
+    {
+#ifdef GDK_WINDOWING_X11
+      guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
+      if (timestamp != GDK_CURRENT_TIME)
+        gdk_x11_window_set_user_time (widget->window, timestamp);
+#endif
+      if (!startup_id_is_fake (priv->startup_id)) 
+        gdk_window_set_startup_id (widget->window, priv->startup_id);
+    }
 
   /* Icons */
   gtk_window_realize_icon (window);
index 4d4fc53d7e4b277c65b7b434af0a9a0a53e900e8..c1ff6892d3bb8ef8cd76cff683433e428713bbee 100644 (file)
@@ -178,6 +178,8 @@ void       gtk_window_set_wmclass              (GtkWindow           *window,
                                                const gchar         *wmclass_class);
 void       gtk_window_set_role                 (GtkWindow           *window,
                                                 const gchar         *role);
+void       gtk_window_set_startup_id           (GtkWindow           *window,
+                                                const gchar         *startup_id);
 G_CONST_RETURN gchar *gtk_window_get_role      (GtkWindow           *window);
 void       gtk_window_add_accel_group          (GtkWindow           *window,
                                                GtkAccelGroup       *accel_group);